#include "stm32f4xx.h"
#include "stm32f4xx_tim.h"

#define HW_DELAY_TIMER              TIM7
#define HW_DELAY_TIMER_MAX_COUNT    40000  // 4MHz, 10ms

/**
 * @brief Initialize hardware delay timer (TIM7)
 * @return 0 on success
 */
int hw_delay_init(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    /* Time base configuration */
    TIM_TimeBaseStructure.TIM_Period = HW_DELAY_TIMER_MAX_COUNT - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = 21 - 1;  // 84MHz / 21 = 4MHz
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

    TIM_TimeBaseInit(HW_DELAY_TIMER, &TIM_TimeBaseStructure);

    /* Enable TIM7 */
    TIM_Cmd(HW_DELAY_TIMER, ENABLE);

    return 0;
}

/**
 * @brief Get current timer counter value
 * @return Current counter value
 */
static uint32_t HwMicroTimerGetCnt(void)
{
    return TIM_GetCounter(HW_DELAY_TIMER);
}

/**
 * @brief Microsecond delay function
 * @param us: Microseconds to delay (should be less than 1000)
 * @return 0 on success
 */
int hw_delay_us(uint32_t us) // us should be less than 1000
{
    us *= 4;  // Convert microseconds to timer ticks (4MHz = 0.25us per tick)
    us %= HW_DELAY_TIMER_MAX_COUNT;

    uint32_t start = HwMicroTimerGetCnt();

    /* Handle timer overflow case */
    if (us + start > HW_DELAY_TIMER_MAX_COUNT) {
        /* Wait for timer to wrap around */
        while (HwMicroTimerGetCnt() >= start);

        /* Adjust remaining delay after wrap */
        us -= (HW_DELAY_TIMER_MAX_COUNT - start);
        start = 0;
    }

    /* Wait for the remaining delay */
    while ((HwMicroTimerGetCnt() - start) < us);

    return 0;
}
